package com.thilux.servicemanager.util.reflection;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;

public class PackageReflection {

    private String packageName;

    public PackageReflection(String packageName) {

	this.packageName = packageName;
    }

    public List<Class<?>> getClasses() throws Exception {
	ClassLoader loader = Thread.currentThread().getContextClassLoader();
	return getClasses(loader, packageName);
    }

    private List<Class<?>> getClasses(ClassLoader loader, String packageName) {
	List<Class<?>> classes = new LinkedList<Class<?>>();
	String path = packageName.replace('.', '/');
	Enumeration<URL> resources = null;
	try {
	    resources = loader.getResources(path);
	} catch (IOException e1) {
	    // TODO Auto-generated catch block
	    e1.printStackTrace();
	}
	if (resources != null) {
	    while (resources.hasMoreElements()) {
		String filePath = resources.nextElement().getFile();
		// WINDOWS HACK
		if (filePath.indexOf("%20") > 0)
		    filePath = filePath.replaceAll("%20", " ");
		if (filePath != null) {
		    if ((filePath.indexOf("!") > 0)
			    & (filePath.indexOf(".jar") > 0)) {
			String jarPath = filePath.substring(0,
				filePath.indexOf("!")).substring(
				filePath.indexOf(":") + 1);
			// WINDOWS HACK
			if (jarPath.indexOf(":") >= 0)
			    jarPath = jarPath.substring(1);
			try {
			    classes.addAll(getFromJARFile(jarPath, path));
			} catch (FileNotFoundException e) {
			    // TODO Auto-generated catch block
			    e.printStackTrace();
			} catch (IOException e) {
			    // TODO Auto-generated catch block
			    e.printStackTrace();
			} catch (ClassNotFoundException e) {
			    // TODO Auto-generated catch block
			    e.printStackTrace();
			}
		    } else {
			try {
			    classes.addAll(getFromDirectory(new File(filePath),
			    	packageName));
			} catch (ClassNotFoundException e) {
			    // TODO Auto-generated catch block
			    e.printStackTrace();
			}
		    }
		}
	    }
	}
	return classes;
    }

    private List<Class<?>> getFromDirectory(File directory, String packageName) throws ClassNotFoundException {
	List<Class<?>> classes = new LinkedList<Class<?>>();
	if (directory.exists()) {
	    for (String file : directory.list()) {
		if (file.endsWith(".class")) {
		    String name = packageName + '.'
			    + stripFilenameExtension(file);
		    Class<?> clazz = Class.forName(name);
		    classes.add(clazz);
		}
	    }
	}
	return classes;
    }

    private List<Class<?>> getFromJARFile(String jar, String packageName) throws FileNotFoundException, IOException, ClassNotFoundException {
	List<Class<?>> classes = new LinkedList<Class<?>>();
	JarInputStream jarFile = new JarInputStream(new FileInputStream(jar));
	JarEntry jarEntry;
	do {
	    jarEntry = jarFile.getNextJarEntry();
	    if (jarEntry != null) {
		String className = jarEntry.getName();
		if (className.endsWith(".class")) {
		    className = stripFilenameExtension(className);
		    if (className.startsWith(packageName))
			classes.add(Class.forName(className.replace('/', '.')));
		}
	    }
	} while (jarEntry != null);
	return classes;
    }
    
    private String stripFilenameExtension(String className){
	
	return className.replace(".class", "");
	
    }

}
